home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 4
/
Aminet 4 - November 1994.iso
/
aminet
/
dev
/
obero
/
oberon_lib.lha
/
oberon-a
/
source1.lha
/
source
/
Library
/
StdIO.mod
< prev
next >
Wrap
Text File
|
1994-08-08
|
11KB
|
377 lines
(***************************************************************************
$RCSfile: StdIO.mod $
Description: Simple formatted I/O using the standard input and output
handles.
Created by: fjc (Frank Copeland)
$Revision: 1.8 $
$Author: fjc $
$Date: 1994/08/08 16:25:24 $
Copyright © 1994, Frank Copeland.
This file is part of the Oberon-A Library.
See Oberon-A.doc for conditions of use and distribution.
***************************************************************************)
MODULE StdIO;
(*
** $C= CaseChk $I= IndexChk $L+ LongAdr $N- NilChk
** $P- PortableCode $R= RangeChk $S= StackChk $T= TypeChk
** $V= OvflChk $Z= ZeroVars
*)
IMPORT
SYS := SYSTEM, Exec, Dos, WB := Workbench, Icon, Args, Errors,
Reals;
VAR
enableBreak * : BOOLEAN;
CONST
DefWbConsole = "CON:40/12/480/150/Oberon-A StdIO Window";
maxD = 9;
VAR
WbConsole : Dos.FileHandlePtr;
(*------------------------------------*)
PROCEDURE^ CheckBreak ();
(*------------------------------------*)
PROCEDURE Write* (ch : CHAR);
BEGIN (* Write *)
CheckBreak ();
SYS.PUTREG (0, Dos.base.Write (Dos.base.Output(), ch, 1))
END Write;
(*------------------------------------*)
PROCEDURE WriteLn*;
BEGIN (* WriteLn *)
Write (0AX)
END WriteLn;
(*------------------------------------*)
PROCEDURE WriteStr* (s : ARRAY OF CHAR);
(* $D- Disables copying of dynamic array parameters. *)
BEGIN (* WriteStr *)
CheckBreak ();
SYS.PUTREG (0, Dos.base.Write (Dos.base.Output (), s, SYS.STRLEN (s)))
END WriteStr;
(*
** $S- Disable compiler stack checking.
**
** CheckBreak() is always called from within a procedure which has already
** done it, and PutCh() won't work with it on.
*)
(*------------------------------------*)
PROCEDURE CheckBreak ();
VAR signals : SET;
BEGIN (* CheckBreak *)
IF enableBreak THEN
signals := Exec.base.SetSignal ({}, {});
IF Dos.sigBreakCtrlC IN signals THEN
enableBreak := FALSE;
WriteStr ("\n***BREAK -- User aborted\n");
HALT (Dos.returnWarn)
END
END
END CheckBreak;
(*------------------------------------*)
PROCEDURE* PutCh ();
BEGIN (* PutCh *)
SYS.INLINE (16C0H) (* MOVE.B D0,(A3)+ *)
END PutCh;
(* $S= Enable compiler stack checking *)
(*------------------------------------*)
PROCEDURE WriteInt* (i : LONGINT);
VAR
str : ARRAY 256 OF CHAR;
BEGIN (* WriteInt *)
Exec.base.OldRawDoFmtL ("%ld", i, PutCh, SYS.ADR (str));
WriteStr (str)
END WriteInt;
(*------------------------------------*)
PROCEDURE WriteHex* (i : LONGINT);
VAR
str : ARRAY 256 OF CHAR;
BEGIN (* WriteHex *)
Exec.base.OldRawDoFmtL ("%lx", i, PutCh, SYS.ADR (str));
WriteStr (str)
END WriteHex;
(*
* The following WriteReal* and WriteLongReal* procedures have been pinched
* from Module Texts and have been somewhat modified from the original code
* described in "Project Oberon".
*)
(*------------------------------------*)
PROCEDURE WriteReal * ( x : REAL; n : INTEGER );
VAR e : INTEGER; x0 : REAL; d : ARRAY maxD OF CHAR;
BEGIN (* WriteReal *)
(*
* This implementation uses Motorola FFP format reals instead of IEEE
* single-precision reals. The Project Oberon code has been modified to
* remove the special-case handling of unnormal and NaN values and assume
* 7-bit exponents instead of 8-bit.
*)
e := Reals.Expo (x);
IF n <= 9 THEN n := 3 ELSE DEC (n, 6) END;
REPEAT Write (" "); DEC (n) UNTIL n <= 8;
(* there are 2 < n <= 8 digits to be written *)
IF x < 0.0 THEN Write ("-"); x := -x ELSE Write (" ") END;
e := (e - 64) * 77 DIV 256;
IF e >= 0 THEN x := x / Reals.Ten (e) ELSE x := Reals.Ten (-e) * x END;
IF x >= 10.0 THEN x := 0.1 * x; INC (e) END;
x0 := Reals.Ten (n - 1); x := x0 * x + 0.5;
IF x >= 10.0 * x0 THEN x := x * 0.1; INC (e) END;
Reals.Convert (x, n, d);
DEC (n); Write (d [n]); Write (".");
REPEAT DEC (n); Write (d [n]) UNTIL n = 0;
Write ("E");
IF e < 0 THEN Write ("-"); e := -e ELSE Write ("+") END;
Write (CHR (e DIV 10 + 30H)); Write (CHR (e MOD 10 + 30H))
END WriteReal;
(*------------------------------------*)
PROCEDURE WriteRealFix * ( x : REAL; n, k : INTEGER );
VAR e, i : INTEGER; sign : CHAR; x0 : REAL; d : ARRAY maxD OF CHAR;
(*------------------------------------*)
PROCEDURE seq ( ch : CHAR; n : LONGINT );
BEGIN (* seq *)
WHILE n > 0 DO Write (ch); DEC (n) END
END seq;
(*------------------------------------*)
PROCEDURE dig (n : INTEGER);
BEGIN (* dig *)
WHILE n > 0 DO
DEC (i); Write (d [i]); DEC (n)
END;
END dig;
BEGIN (* WriteRealFix *)
(*
* This implementation uses Motorola FFP format reals instead of IEEE
* single-precision reals. The Project Oberon code has been modified to
* remove the special-case handling of unnormal and NaN values and assume
* 7-bit exponents instead of 8-bit.
*)
IF k < 0 THEN k := 0 END;
e := (Reals.Expo (x) - 64) * 77 DIV 256;
IF x < 0.0 THEN sign := "-"; x := -x ELSE sign := " " END;
IF e >= 0 THEN (* x >= 1.0, 77/256 = log 2 *) x := x / Reals.Ten (e)
ELSE (* x < 1.0 *) x := Reals.Ten (-e) * x END;
IF x >= 10.0 THEN x := 0.1 * x; INC (e) END;
(* 1 <= x < 10 *)
IF k + e >= maxD - 1 THEN k := maxD - 1 - e
ELSIF k + e < 0 THEN k := -e; x := 0.0
END;
x0 := Reals.Ten (k + e); x := x0 * x + 0.5;
IF x >= 10.0 * x0 THEN INC (e) END;
(* e = no. of digits before decimal point *)
INC (e); i := k + e; Reals.Convert (x, i, d);
IF e > 0 THEN
seq (" ", n - e - k - 2); Write (sign); dig (e); Write (".");
dig (k)
ELSE
seq (" ", n - k - 3); Write (sign); Write ("0"); Write (".");
seq ("0", -e); dig (k + e)
END; (* ELSE *)
END WriteRealFix;
(*------------------------------------*)
PROCEDURE WriteRealHex * ( x : REAL );
VAR d : ARRAY 9 OF CHAR;
BEGIN (* WriteRealHex *)
Reals.ConvertH (x, d); d [8] := 0X; WriteStr (d)
END WriteRealHex;
(*------------------------------------*)
PROCEDURE WriteLongReal * ( x : LONGREAL; n : INTEGER );
BEGIN (* WriteLongReal *)
(*
* In this implementation, LONGREAL and REAL types are the same, so this
* procedure is implemented as a call to WriteReal ().
*)
WriteReal (SHORT (x), n)
END WriteLongReal;
(*------------------------------------*)
PROCEDURE WriteLongRealHex * ( x : LONGREAL );
BEGIN (* WriteLongRealHex *)
(*
* In this implementation, LONGREAL and REAL types are the same, so this
* procedure is implemented as a call to WriteRealHex ().
*)
WriteRealHex (SHORT (x))
END WriteLongRealHex;
(*------------------------------------*)
(* $D- Disables copying of dynamic array parameters. *)
PROCEDURE WriteF* (
fs : ARRAY OF CHAR; VAR f : ARRAY OF SYS.LONGWORD);
VAR
str : ARRAY 256 OF CHAR;
BEGIN (* WriteF *)
Exec.base.OldRawDoFmtL (fs, f, PutCh, SYS.ADR (str));
WriteStr (str)
END WriteF;
(*------------------------------------*)
(* $D- Disables copying of dynamic array parameters. *)
PROCEDURE WriteF1*
( fs : ARRAY OF CHAR;
param1 : SYS.LONGWORD);
VAR str : ARRAY 256 OF CHAR;
BEGIN (* WriteF1 *)
Exec.base.OldRawDoFmtL (fs, param1, PutCh, SYS.ADR (str));
WriteStr (str)
END WriteF1;
(*------------------------------------*)
(* $D- Disables copying of dynamic array parameters. *)
PROCEDURE WriteF2* (
fs : ARRAY OF CHAR; param1, param2 : SYS.LONGWORD);
VAR str : ARRAY 256 OF CHAR; t : SYS.LONGWORD;
BEGIN (* WriteF2 *)
t := param1; param1 := param2; param2 := t;
Exec.base.OldRawDoFmtL (fs, param2, PutCh, SYS.ADR (str));
WriteStr (str)
END WriteF2;
(*------------------------------------*)
(* $D- Disables copying of dynamic array parameters. *)
PROCEDURE WriteF3* (
fs : ARRAY OF CHAR; param1, param2, param3 : SYS.LONGWORD);
VAR str : ARRAY 256 OF CHAR; t : SYS.LONGWORD;
BEGIN (* WriteF3 *)
t := param1; param1 := param3; param3 := t;
Exec.base.OldRawDoFmtL (fs, param3, PutCh, SYS.ADR (str));
WriteStr (str)
END WriteF3;
(*------------------------------------*)
PROCEDURE Read* (VAR ch : CHAR);
BEGIN (* Read *)
CheckBreak ();
IF Dos.base.Read (Dos.base.Input (), ch, 1) < 1 THEN ch := 0X END;
END Read;
(*------------------------------------*)
PROCEDURE ReadStr* (VAR str : ARRAY OF CHAR);
VAR ch : CHAR; index, limit : INTEGER;
BEGIN (* ReadStr *)
(* Skip white space *)
REPEAT Read (ch) UNTIL (ch # " ") & (ch # 09X);
(* Read until control char *)
index := 0; limit := SHORT (LEN (str));
WHILE (ch >= " ") & (index < limit) DO
str [index] := ch; INC (index); Read (ch);
END; (* WHILE *)
str [index] := 0X;
(* Skip rest of line if any *)
WHILE ch >= " " DO Read (ch) END;
END ReadStr;
(* $L- Access global variables through A4 *)
(*------------------------------------*)
PROCEDURE* CloseWbConsole ();
BEGIN (* CloseWbConsole *)
IF WbConsole # NIL THEN Dos.base.OldClose (WbConsole) END;
END CloseWbConsole;
(*------------------------------------*)
PROCEDURE SetupWbConsole ();
VAR
oldDir : Dos.FileLockPtr;
console : Exec.STRPTR;
diskObj : WB.DiskObjectPtr;
toolTypes : WB.ToolTypePtr;
process : Dos.ProcessPtr;
conTask : Exec.MsgPortPtr;
BEGIN (* SetupWbConsole *)
(* Make sure icon.library is open *)
Icon.OpenLib (TRUE);
(* First CD to the app's directory *)
oldDir := Dos.base.CurrentDir (Args.ArgList [0].lock);
(* Attempt to load the app's icon *)
diskObj := Icon.base.GetDiskObject (Args.ArgList [0].name^);
IF diskObj # NIL THEN
(* Look for a "WINDOW=" tooltype *)
console := Icon.base.FindToolType (diskObj.toolTypes, "WINDOW");
(*
* We will free diskObj AFTER we have finished with console. Guess
* who got it wrong? :-)
*)
END; (* IF *)
(* Back to where we started *)
oldDir := Dos.base.CurrentDir (oldDir);
(* Open the console window *)
IF console = NIL THEN console := SYS.ADR (DefWbConsole) END;
WbConsole := Dos.base.Open (console^, Dos.modeNewFile);
IF diskObj # NIL THEN Icon.base.FreeDiskObject (diskObj) END;
Errors.Assert (WbConsole # NIL, "Could not open StdIO window");
(*
* Set the console task (so Input(), Output() & Open("*", mode) will
* work). This is from Commodore's startup.asm.
*)
process := SYS.VAL (Dos.ProcessPtr, Exec.base.FindTask (NIL));
process.cis := WbConsole;
process.cos := WbConsole;
conTask := WbConsole.type;
IF conTask # NIL THEN process.consoleTask := conTask END;
SYS.SETCLEANUP (CloseWbConsole);
END SetupWbConsole;
BEGIN
enableBreak := TRUE;
IF ~Args.IsCLI THEN SetupWbConsole () END
END StdIO.